/*
 * @(#)Xfdm.java        1.0 2000/05/09
 *
 * This file is part of Xfuzzy 3.0, a design environment for fuzzy logic
 * based systems.
 *
 * (c) 2000 IMSE-CNM. The authors may be contacted by the email address:
 *                    xfuzzy-team@imse.cnm.es
 *
 * Xfuzzy is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation.
 *
 * Xfuzzy is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 */

package xfuzzy.xfdm.view;

import xfuzzy.*;
import xfuzzy.lang.*;
import xfuzzy.util.*;
import xfuzzy.xfdm.model.*;
import xfuzzy.xfdm.model.algorithm.*;
import xfuzzy.xfdm.view.listener.*;
import xfuzzy.xfds.XfdsDataSet;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;

/**
 * Herramienta de extracci�n de reglas difusas a partir de datos
 * 
 * @author Francisco Jos� Moreno Velo
 *
 */
public class Xfdm extends JFrame implements IXfdmFrame {

	//----------------------------------------------------------------------------//
	//                            COSTANTES PRIVADAS                              //
	//----------------------------------------------------------------------------//

	/**
	 * C�digo asociado a la clase serializable
	 */
	private static final long serialVersionUID = 95505666603011L;

	//----------------------------------------------------------------------------//
	//                            MIEMBROS PRIVADOS                               //
	//----------------------------------------------------------------------------//

	/**
	 * Ventana principal del entorno
	 */
	private Xfuzzy xfuzzy;
	
	/**
	 * Sistema difuso sobre el que construir las reglas
	 */
	private Specification spec;
	
	/**
	 * Configuraci�n del proceso
	 */
	private XfdmConfig config;
	
	/**
	 * Campos de texto de la ventana principal de la herramienta
	 */
	private XTextForm text[];
	
	/**
	 * Barra de comandos
	 */
	private XCommandForm form;
	
	//----------------------------------------------------------------------------//
	//                                CONSTRUCTOR                                 //
	//----------------------------------------------------------------------------//

	/**
	 * Constructor
	 */
	public Xfdm(Xfuzzy xfuzzy, Specification spec){
		super("Xfdm");
		this.xfuzzy = xfuzzy;
		this.spec = spec;
		this.config = new XfdmConfig();
		this.config.setSpecification(spec);
		build();
		refresh();
	}

	//----------------------------------------------------------------------------//
	//                             M�TODOS P�BLICOS                               //
	//----------------------------------------------------------------------------//

	/**
	 * Actualiza la configuraci�n
	 */
	public void setConfig(XfdmConfig xfdmc) {
		this.config = xfdmc;
		refresh();
	}

	/**
	 * Obtiene la configuraci�n
	 */
	public XfdmConfig getConfig() {
		return this.config;
	}

	/**
	 * Obtiene la especificaci�n del sistema
	 */
	public Specification getSpecification() {
		return this.spec;
	}

	/**
	 * Actualiza los campos de la ventana
	 */
	public void refresh() {

		if(config.getDataSetFile() != null) 
			text[0].setText(config.getDataSetFile().getAbsolutePath());
		else text[0].setText("");

		if(config.getAlgorithm() != null) text[1].setText(config.getAlgorithm().toString());
		else text[1].setText("");

		if(config.testInputStyle()) text[2].setText("Configured");
		else text[2].setText("Unconfigured");

		if(config.getSystemStyle() != null) text[3].setText("Configured");
		else text[3].setText("Unconfigured");

		if(config.getDataTestFile() != null) 
			text[4].setText(config.getDataTestFile().getAbsolutePath());
		else text[4].setText("");

		if(config.getLogFile() != null) 
			text[5].setText(config.getLogFile().getAbsolutePath());
		else text[5].setText("");

		int step = config.getStep();
		text[0].setLabelEnabled(step >= 0);
		text[1].setLabelEnabled(step >= 1);
		text[2].setLabelEnabled(step >= 2);
		text[3].setLabelEnabled(step >= 3);
		text[4].setLabelEnabled(step >= 4);
		text[5].setLabelEnabled(step >= 4);
		form.setEnabled(2, step>=4);
	}

	/**
	 * Finaliza externamente
	 */
	public void finish(String msg) {
		XDialog.showMessage(text[2],msg);
		close();
	}

	/**
	 * Acci�n del men� de algoritmos
	 */
	public void actionAlgorithm() {
		XfdsDataSet ds = config.getDataSet();
		if(ds.isAClassification()) {
			JPopupMenu menu = buildClassificationMenu();
			menu.show(text[1],0,text[1].getHeight());
		} else {
			JPopupMenu menu = buildRegressionMenu();
			menu.show(text[1],0,text[1].getHeight());			
		}
	}

	/**
	 * Acci�n del algoritmo Flat System	
	 */
	public void actionFlat() {
		config.setAlgorithm(new XfdmFlatSystem());
		refresh();
	}

	/**
	 * Acci�n del algoritmo de Wang y Mendel
	 */
	public void actionWang() {
		config.setAlgorithm(new XfdmWangMendel());
		refresh();
	}

	/**
	 * Acci�n del algoritmo FuzzyID3
	 */
	public void actionFuzzyID3() {
		XfdmAlgorithm alg = XfdmFuzzyID3Dialog.showDialog(this,config.getAlgorithm());
		if(alg != null) config.setAlgorithm(alg);
		if(config.getSystemStyle() != null) {
			config.getSystemStyle().setDefuzMethod(XfdmSystemStyle.CLASSIFICATION);
		}
		refresh();
	}

	/**
	 * Acci�n del algoritmo FuzzConRI
	 */
	public void actionFuzzConRI() {
		XfdmAlgorithm alg = XfdmFuzzConRIDialog.showDialog(this,config.getAlgorithm());
		if(alg != null) config.setAlgorithm(alg);
		if(config.getSystemStyle() != null) {
			config.getSystemStyle().setDefuzMethod(XfdmSystemStyle.CLASSIFICATION);
		}
		refresh();
	}

	/**
	 * Acci�n del algoritmo FuzzyCN2
	 */
	public void actionFuzzyCN2() {
		XfdmAlgorithm alg = XfdmFuzzyCN2Dialog.showDialog(this,config.getAlgorithm());
		if(alg != null) config.setAlgorithm(alg);
		if(config.getSystemStyle() != null) {
			config.getSystemStyle().setDefuzMethod(XfdmSystemStyle.CLASSIFICATION);
		}
		refresh();
	}
	
	/**
	 * Acci�n del algoritmo de Nauck
	 */
	public void actionNauck() {
		XfdmAlgorithm alg = XfdmNauckDialog.showDialog(this,config.getAlgorithm());
		if(alg != null) config.setAlgorithm(alg);
		if(config.getSystemStyle() != null) {
			config.getSystemStyle().setDefuzMethod(XfdmSystemStyle.CLASSIFICATION);
		}
		refresh();
	}

	/**
	 * Accion del algoritmo de Senhadji
	 */
	public void actionSenhadji() {
		XfdmAlgorithm alg = XfdmSenhadjiDialog.showDialog(this,config.getAlgorithm());
		if(alg != null) config.setAlgorithm(alg);
		if(config.getSystemStyle() != null) {
			config.getSystemStyle().setDefuzMethod(XfdmSystemStyle.CLASSIFICATION);
		}
		refresh();
	}

	/**
	 * Acci�n del algoritmo de Incremental Grid Partition
	 */
	public void actionIncGrid() {
		XfdmAlgorithm alg = XfdmIncGridDialog.showDialog(this,config.getAlgorithm());
		if(alg != null) config.setAlgorithm(alg);
		if(config.getSystemStyle() != null && 
				config.getSystemStyle().getDefuzMethod() != XfdmSystemStyle.FUZZYMEAN &&
				config.getSystemStyle().getDefuzMethod() != XfdmSystemStyle.WEIGHTED) {
			config.getSystemStyle().setDefuzMethod(XfdmSystemStyle.FUZZYMEAN);
		}
		refresh();
	}

	/**
	 * Acci�n del algoritmo de Incremental Clustering
	 */
	public void actionIncCluster() {
		XfdmAlgorithm alg = XfdmIncClustDialog.showDialog(this,config.getAlgorithm());
		if(alg != null) config.setAlgorithm(alg);
		if(config.getSystemStyle() != null && 
				config.getSystemStyle().getDefuzMethod() == XfdmSystemStyle.CLASSIFICATION) {
			config.getSystemStyle().setDefuzMethod(XfdmSystemStyle.FUZZYMEAN);
		}
		refresh();
	}

	/**
	 * Acci�n del algoritmo de Fixed Clustering
	 */
	public void actionFixedCluster() {
		XfdmAlgorithm alg = XfdmClusteringDialog.showDialog(this,config.getAlgorithm());
		if(alg != null) config.setAlgorithm(alg);
		if(config.getSystemStyle() != null && 
				config.getSystemStyle().getDefuzMethod() == XfdmSystemStyle.CLASSIFICATION) {
			config.getSystemStyle().setDefuzMethod(XfdmSystemStyle.FUZZYMEAN);
		}
		refresh();
	}

	/**
	 * Acci�n de selecci�n del conjunto de datos
	 */
	public void actionDataSet() {
		File root = this.config.getDataSetFile();
		if(root == null && xfuzzy != null) root = xfuzzy.getWorkingDirectory();
		if(root == null && xfuzzy == null)
			root = new File(System.getProperty("user.dir"));
		XFileChooser chooser = new XFileChooser(root, XFileChooser.SELECT);
		if(chooser.showDialog() != XFileChooser.CANCELED) 
			config.setDataSet( chooser.getSelectedFile() );
		refresh();
	}

	/**
	 * Acci�n de selecci�n del conjunto de datos de test
	 */
	public void actionDataTest() {
		File root = this.config.getDataTestFile();
		if(root == null && xfuzzy != null) root = xfuzzy.getWorkingDirectory();
		if(root == null && xfuzzy == null)
			root = new File(System.getProperty("user.dir"));
		XFileChooser chooser = new XFileChooser(root, XFileChooser.SELECT);
		if(chooser.showDialog() != XFileChooser.CANCELED) 
			config.setDataTest( chooser.getSelectedFile() );
		refresh();
	}
	
	/**
	 * Acci�n de selecci�n del fichero de log
	 */
	public void actionLog() {
		File root = this.config.getLogFile();
		if(root == null && xfuzzy != null) root = xfuzzy.getWorkingDirectory();
		if(root == null && xfuzzy == null)
			root = new File(System.getProperty("user.dir"));
		XFileChooser chooser = new XFileChooser(root, XFileChooser.SELECT);
		if(chooser.showDialog() != XFileChooser.CANCELED) 
			config.setLogFile( chooser.getSelectedFile() );
		refresh();
	}


	/**
	 * Acci�n de selecci�n del estilo de variables de entrada
	 */
	public void actionInputs() {
		XfdmInputStyleDialog editor = new XfdmInputStyleDialog(this);
		editor.setVisible(true);
		refresh();
	}

	/**
	 * Acci�n de selecci�n del estilo de sistema
	 */
	public void actionSystem() {
		XfdmSystemStyleDialog editor = new XfdmSystemStyleDialog(this);
		editor.setVisible(true);
		refresh();
	}

	/**
	 * Acci�n de carga de la configuraci�n
	 */
	public void actionLoad() {
		File wdir = xfuzzy.getWorkingDirectory();
		XFileChooser chooser = new XFileChooser(wdir,XFileChooser.LOAD);
		chooser.addFileFilter(".xml","Xfuzzy Configuration Files");
		int returnVal = chooser.showDialog();
		if(returnVal != XFileChooser.SELECTED) return;
		File file = chooser.getSelectedFile();
		
		XmlParser parser = new XmlParser();
		if(!parser.parseXML(file)) {
			xfuzzy.log(parser.getErrorMessage());
			Toolkit.getDefaultToolkit().beep();			
			return;
		}
		XfdmConfig xfdmc = parser.getXfdmConfig();
		if(xfdmc != null) {
			config = xfdmc;
			refresh();
		} else {
			XDialog.showMessage(text[2],parser.getErrorMessage());
			Toolkit.getDefaultToolkit().beep();
		}				
	}

	/**
	 * Acci�n de almacenamiento de la configuraci�n
	 */
	public void actionSave() {		
		File wdir = xfuzzy.getWorkingDirectory();
		XFileChooser chooser = new XFileChooser(wdir,XFileChooser.SAVE);
		int returnVal = chooser.showDialog();
		if(returnVal != XFileChooser.SELECTED) return;
		File file = chooser.getSelectedFile();
		
		boolean append = false;
		if(file.exists()) {
			String question[] = new String[3];
			question[0] = "File "+file.getName()+" already exists.";
			question[1] = "Do you want to overwrite this file?";
			question[2] = "(Otherwise the code will be append at the end of the file)";
			int result = XDialog.showYNQuestion(this, question);
			if(result == XDialog.CANCEL) return;
			if(result == XDialog.NO) append = true;
		}
		config.save(file,append);
	}

	/**
	 * Acci�n de creaci�n del sistema difuso
	 */
	public void actionCreate() {
		form.setLabel(2,"Creating");
		form.setEnabled(0,false);
		form.setEnabled(1,false);
		form.setEnabled(2,false);
		form.setEnabled(3,false);
		repaint();
		new XfdmProcess(this);
	}

	/**
	 * Acci�n de cerrar la ventana
	 */
	public void close() {
		setVisible(false); 
	}
	
	//----------------------------------------------------------------------------//
	//                             M�TODOS PRIVADOS                               //
	//----------------------------------------------------------------------------//

	/**
	 * Generaci�n de la ventana
	 */
	private void build() {
		ActionListener listener = new XfdmActionListener(this);

		String lb[] = {"Load", "Save", "Create System", "Close"};
		String cm[] = {"Load", "Save", "Create", "Close"};
		form = new XCommandForm(lb,cm,listener);
		form.setCommandWidth(150);
		form.block();

		text = new XTextForm[6];
		text[0] = new XTextForm("Data Set",listener);
		text[0].setActionCommand("DataSet");
		text[0].setEditable(false);
		text[1] = new XTextForm("Algorithm",listener);
		text[1].setActionCommand("Algorithm");
		text[1].setEditable(false);
		text[2] = new XTextForm("Input style",listener);
		text[2].setActionCommand("Inputs");
		text[2].setEditable(false);
		text[3] = new XTextForm("System style",listener);
		text[3].setActionCommand("System");
		text[3].setEditable(false);
		text[4] = new XTextForm("Test Data",listener);
		text[4].setActionCommand("Test");
		text[4].setEditable(false);
		text[5] = new XTextForm("Log File",listener);
		text[5].setActionCommand("Log");
		text[5].setEditable(false);
		XTextForm.setWidth(text);

		Container content = getContentPane();
		content.setLayout(new BoxLayout(content,BoxLayout.Y_AXIS));
		content.add(new XLabel("Data Mining"));
		content.add(Box.createVerticalStrut(5));
		content.add(text[0]);
		content.add(text[1]);
		content.add(text[2]);
		content.add(text[3]);		
		content.add(text[4]);		
		content.add(text[5]);		
		content.add(Box.createVerticalStrut(5));
		content.add(form);

		setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
		setIconImage( XfuzzyIcons.xfuzzy.getImage() );
		addWindowListener(new XfdmWindowListener(this));
		pack();
		setLocation();
	}

	/**
	 * Men� de algoritmos de clasificaci�n
	 */
	private JPopupMenu buildClassificationMenu() {
		ActionListener listener = new XfdmActionListener(this);
		
		String label0[] = { "Flat system", "Fuzzy ID3", "FuzzConRI", "FuzzyCN2", "Wang & Mendel", "Nauck", "Senhadji",
		"Incremental Grid" };
		String command0[] = { "Flat", "FuzzyID3", "FuzzConRI", "FuzzyCN2", "Wang", "Nauck", "Senhadji", "IncGrid" };
		boolean enable0[] = { false, true, true, true, true, true, true, false };
		String label1[] = { "Incremental Clustering", "Fixed Clustering" };
		String command1[] = { "IncCluster", "FixedCluster" };
		boolean enable1[] = { false, false };

		JMenu[] fam = new JMenu[2];
		fam[0] = new JMenu("Structure-oriented algorithms");
		fam[0].setFont(XConstants.font);
		for(int i=0; i<label0.length; i++) {
			JMenuItem item = new JMenuItem(label0[i]);
			item.setFont(XConstants.font);
			item.addActionListener(listener);
			item.setActionCommand(command0[i]);
			item.setEnabled(enable0[i]);
			fam[0].add(item);
		}

		fam[1] = new JMenu("Cluster-oriented algorithms");
		fam[1].setFont(XConstants.font);
		for(int i=0; i<label1.length; i++) {
			JMenuItem item = new JMenuItem(label1[i]);
			item.setFont(XConstants.font);
			item.addActionListener(listener);
			item.setActionCommand(command1[i]);
			item.setEnabled(enable1[i]);
			fam[1].add(item);
		}

		JPopupMenu menu = new JPopupMenu();
		menu.add(fam[0]);
		menu.add(fam[1]);
		return menu;
	}

	/**
	 * Men� de algoritmos de clasificaci�n
	 */
	private JPopupMenu buildRegressionMenu() {
		ActionListener listener = new XfdmActionListener(this);
		
		String label0[] = { "Flat system", "Fuzzy ID3", "FuzzConRI", "FuzzyCN2", "Wang & Mendel", "Nauck", "Senhadji",
		"Incremental Grid" };
		String command0[] = { "Flat", "FuzzyID3", "FuzzConRI", "FuzzyCN2", "Wang", "Nauck", "Senhadji", "IncGrid" };
		boolean enable0[] = { true, false, false, false, true, false, false, true };
		String label1[] = { "Incremental Clustering", "Fixed Clustering" };
		String command1[] = { "IncCluster", "FixedCluster" };
		boolean enable1[] = { true, true };

		JMenu[] fam = new JMenu[2];
		fam[0] = new JMenu("Structure-oriented algorithms");
		fam[0].setFont(XConstants.font);
		for(int i=0; i<label0.length; i++) {
			JMenuItem item = new JMenuItem(label0[i]);
			item.setFont(XConstants.font);
			item.addActionListener(listener);
			item.setActionCommand(command0[i]);
			item.setEnabled(enable0[i]);
			fam[0].add(item);
		}

		fam[1] = new JMenu("Cluster-oriented algorithms");
		fam[1].setFont(XConstants.font);
		for(int i=0; i<label1.length; i++) {
			JMenuItem item = new JMenuItem(label1[i]);
			item.setFont(XConstants.font);
			item.addActionListener(listener);
			item.setActionCommand(command1[i]);
			item.setEnabled(enable1[i]);
			fam[1].add(item);
		}

		JPopupMenu menu = new JPopupMenu();
		menu.add(fam[0]);
		menu.add(fam[1]);
		return menu;
	}

	/**
	 * Coloca la ventana en la pantalla
	 */
	private void setLocation() {
		if(xfuzzy != null) {
			Point loc = xfuzzy.frame.getLocationOnScreen();
			loc.x += 40; loc.y += 200;
			setLocation(loc);
		} else {
			Dimension frame = getSize();
			Dimension screen = getToolkit().getScreenSize();
			setLocation((screen.width - frame.width)/2,(screen.height - frame.height)/2);
		}
	}
	
}
